Aggregating trajectories¶

Binder IPYNB HTML

The aggregation approach implemented in TrajectoryCollectionAggregator is based on Andrienko, N., & Andrienko, G. (2011). Spatial generalization and aggregation of massive movement data. IEEE Transactions on visualization and computer graphics, 17(2), 205-219. and consists of the following main steps:

  1. Extracting characteristic points from the trajectories
  2. Grouping the extracted points by spatial proximity
  3. Computing group centroids and corresponding Voronoi cells
  4. Dividing trajectories into segments according to the Voronoi cells
  5. Counting transitions from one cell to another
In [1]:
import pandas as pd
import geopandas as gpd
import movingpandas as mpd
import shapely as shp
import hvplot.pandas 
import matplotlib.pyplot as plt

from geopandas import GeoDataFrame, read_file
from shapely.geometry import Point, LineString, Polygon
from datetime import datetime, timedelta
from holoviews import opts, dim

import warnings
warnings.filterwarnings('ignore')

plot_defaults = {'linewidth':5, 'capstyle':'round', 'figsize':(9,3), 'legend':True}
opts.defaults(opts.Overlay(active_tools=['wheel_zoom'], frame_width=500, frame_height=400))

mpd.show_versions()
MovingPandas 0.10.rc1

SYSTEM INFO
-----------
python     : 3.9.13 | packaged by conda-forge | (main, May 27 2022, 16:50:36) [MSC v.1929 64 bit (AMD64)]
executable : H:\miniconda3\envs\mpd-ex\python.exe
machine    : Windows-10-10.0.19043-SP0

GEOS, GDAL, PROJ INFO
---------------------
GEOS       : None
GEOS lib   : None
GDAL       : 3.5.0
GDAL data dir: None
PROJ       : 9.0.0
PROJ data dir: H:\miniconda3\pkgs\proj-9.0.0-h1cfcee9_1\Library\share\proj

PYTHON DEPENDENCIES
-------------------
geopandas  : 0.10.2
pandas     : 1.4.2
fiona      : 1.8.21
numpy      : 1.22.4
shapely    : 1.8.2
rtree      : 1.0.0
pyproj     : 3.3.1
matplotlib : 3.5.2
mapclassify: 2.4.3
geopy      : 2.2.0
holoviews  : 1.14.9
hvplot     : 0.8.0
geoviews   : 1.9.5
stonesoup  : 0.1b9
In [2]:
gdf = read_file('../data/geolife_small.gpkg')
traj_collection = mpd.TrajectoryCollection(gdf, 'trajectory_id', t='t')
In [3]:
traj_collection.hvplot(line_width=7.0, tiles='StamenTonerBackground')
Out[3]:

TrajectoryCollectionAggregator¶

In [4]:
help(mpd.TrajectoryCollectionAggregator)
Help on class TrajectoryCollectionAggregator in module movingpandas.trajectory_aggregator:

class TrajectoryCollectionAggregator(builtins.object)
 |  TrajectoryCollectionAggregator(traj_collection, max_distance, min_distance, min_stop_duration, min_angle=45)
 |  
 |  Methods defined here:
 |  
 |  __init__(self, traj_collection, max_distance, min_distance, min_stop_duration, min_angle=45)
 |      Aggregates trajectories by extracting significant points,
 |      clustering those points, and extracting flows between clusters.
 |      
 |      Parameters
 |      ----------
 |      traj_collection : TrajectoryCollection
 |          TrajectoryCollection to be aggregated
 |      max_distance : float
 |          Maximum distance between significant points (distance is
 |          calculated in CRS units, except if the CRS is geographic, e.g.
 |          EPSG:4326 WGS84, then distance is calculated in meters)
 |      min_distance : float
 |          Minimum distance between significant points
 |      min_stop_duration : integer
 |          Minimum duration required for stop detection (in seconds)
 |      min_angle : float
 |          Minimum angle for significant point extraction
 |      
 |      References
 |      ----------
 |      * Andrienko, N., & Andrienko, G. (2011). Spatial generalization and
 |        aggregation of massive movement data. IEEE Transactions on
 |        visualization and computer graphics, 17(2), 205-219.
 |  
 |  get_clusters_gdf(self)
 |      Return the extracted cluster centroids
 |      
 |      Returns
 |      -------
 |      GeoDataFrame
 |          Cluster centroids, incl. the number of clustered significant
 |          points (n).
 |  
 |  get_flows_gdf(self)
 |      Return the extracted flows
 |      
 |      Returns
 |      -------
 |      GeoDataFrame
 |          Flow lines, incl. the number of trajectories summarized in the
 |          flow (weight).
 |  
 |  get_significant_points_gdf(self)
 |      Return the extracted significant points
 |      
 |      Returns
 |      -------
 |      GeoDataFrame
 |          Significant points
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

Generalizing the trip trajectories significantly speeds up the following aggregation step.

In [5]:
generalized = mpd.MinDistanceGeneralizer(traj_collection).generalize(tolerance=100)
In [6]:
aggregator = mpd.TrajectoryCollectionAggregator(generalized, max_distance=1000, min_distance=100, min_stop_duration=timedelta(minutes=5))
In [7]:
pts = aggregator.get_significant_points_gdf()
clusters = aggregator.get_clusters_gdf()
( pts.hvplot(geo=True, tiles='StamenTonerBackground') * 
  clusters.hvplot(geo=True, color='red' ) )
Out[7]:
In [8]:
flows = aggregator.get_flows_gdf()
In [9]:
( flows.hvplot(geo=True, hover_cols=['weight'], line_width=dim('weight')*7, color='#1f77b3', tiles='StamenTonerBackground') * 
  clusters.hvplot(geo=True, color='red', size=dim('n') ) )
Out[9]:
In [ ]: